﻿using System.ComponentModel;
using System.Net;
using System.Text;
using Bzstd.Controllers;
using Bzstd.Utility;
using log4net;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.FileProviders.Physical;
using Microsoft.Extensions.Primitives;
using Microsoft.Web.WebView2.WinForms;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using static Bzstd.Utility.ConfigHelper;

namespace Bzstd.Service;

/// <summary>
/// App初始化
/// </summary>
public static class AppInitializer
{
	private static readonly ILog log = LogManager.GetLogger(typeof(AppInitializer));

	public static readonly Dictionary<string, string> HashMapping = new();

	public static readonly Form MainForm = new();

	/// <summary>
	/// 初始化
	/// </summary>
	public static void Init()
	{
		RegisterGlobalExceptionHandler();
		Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
		InitJson();
		InitWebApp();
		MainForm.Name = MainForm.Text = "Portal 2创意工坊辅助工具";
		MainForm.SuspendLayout();
		var icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath)!;
		var bitmap = icon.ToBitmap();
		bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
		icon = Icon.FromHandle(bitmap.GetHicon());
		MainForm.Icon = icon;
		var webview = new WebView2();
		(webview as ISupportInitialize).BeginInit();
		webview.Dock = DockStyle.Fill;
		webview.Name = "WebView";
		webview.Source = new Uri("http://127.0.0.1:8877", UriKind.Absolute);
		MainForm.Controls.Add(webview);
		MainForm.ClientSize = new Size(1366, 768);
		MainForm.MinimumSize = new Size(800, 600);
		(webview as ISupportInitialize).EndInit();
		MainForm.ResumeLayout();
		Application.Run(MainForm);
	}

	/// <summary>
	/// 初始化json
	/// </summary>
	private static void InitJson()
	{
		// 设置json
		JsonConvert.DefaultSettings = () => ConfigJsonSerializerSettings(new());
	}

	private static JsonSerializerSettings ConfigJsonSerializerSettings(JsonSerializerSettings settings)
	{
		// 忽略 null 值
		settings.NullValueHandling = NullValueHandling.Ignore;
		settings.DateParseHandling = DateParseHandling.DateTime;
		settings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
		settings.MaxDepth = 255;

		// 添加额外的转换器
		settings.Converters = ProductAssembly.ExportedTypes
			.Where(typeof(JsonConverter).IsAssignableFrom)
			.Select(t => t.GetConstructor(Type.EmptyTypes)!.Invoke([]))
			.OfType<JsonConverter>()
			.ToList();

		// 使json 序列化 反序列化时 转为camelCase
		settings.ContractResolver = new DefaultContractResolver { NamingStrategy = new CaseNamingStrategy() };
		return settings;
	}

	private static void InitWebApp()
	{
		var builder = WebApplication.CreateBuilder(CommandLineArgs);

		string path = Path.GetFullPath(Path.GetTempFileName());
		using (var src = CommonUtility.GetResourceStream("log4net.config")!)
		using (var dest = File.OpenWrite(path))
		{
			src.CopyTo(dest);
		}
		builder.Logging.ClearProviders().AddLog4Net(path, false);
		File.Delete(path);

		builder.WebHost.UseKestrel(options =>
		{
			options.Listen(IPAddress.Any, IsDebugMode ? 7788 : 8877);
		});

		// Add services to the container.
		builder.Services
			.AddControllers(option => option.Filters.Add<P2ActionFilter>())
			.AddNewtonsoftJson(options => ConfigJsonSerializerSettings(options.SerializerSettings));
		builder.Services.AddCors();
		builder.Services.AddSingleton<P2Service>();
		builder.Services.AddResponseCompression(options => options.EnableForHttps = true);
		builder.Services.AddResponseCaching();

		var app = builder.Build();

		app.UseResponseCompression();
		app.UseResponseCaching();
		app.UseCors(x => x.AllowAnyOrigin().AllowAnyHeader().WithMethods(HttpMethods.Get));

		app.UseStaticFiles(new StaticFileOptions
		{
			FileProvider = new EmbeddedFileProvider(StaticAssembly, "Bzstd.dist"),
			RequestPath = new PathString(string.Empty),
			ServeUnknownFileTypes = true
		});

		app.UseStaticFiles(new StaticFileOptions
		{
			FileProvider = new LocalFileProvider(),
			RequestPath = new PathString("/res"),
			ServeUnknownFileTypes = true
		});

		app.MapFallback(context =>
		{
			context.Response.Redirect("/index.html#/404");
			return Task.CompletedTask;
		});

		app.MapGet(string.Empty, () => Results.Redirect("/index.html"));

		app.MapControllers();

		app.Services.GetRequiredService<P2Service>();

		app.RunAsync();
	}

	private class LocalFileProvider : IFileProvider
	{
		public IFileInfo GetFileInfo(string subpath)
		{
			var path = HashMapping[subpath.Trim('/').Split('/').First()];
			return new PhysicalFileInfo(new FileInfo(path));
		}
		public IDirectoryContents GetDirectoryContents(string subpath) => null;
		public IChangeToken Watch(string filter) => null;
	}

	/// <summary>
	/// 注册全局异常处理器
	/// </summary>
	private static void RegisterGlobalExceptionHandler()
	{
		// 处理非UI线程异常
		AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
		{
			var e = args.ExceptionObject as Exception;
			log.LogException(e, "AppDomain.CurrentDomain.UnhandledException: ");
			Environment.Exit(Math.Abs(e?.GetHashCode() ?? 1));
		};

		// 处理Task异常
		TaskScheduler.UnobservedTaskException += (sender, args) => { log.LogException(args.Exception, "TaskScheduler.UnobservedTaskException: "); };
	}
}
